home *** CD-ROM | disk | FTP | other *** search
/ The Utilities Experience / The Utilities Experience - Volume 1.iso / software / misc / o-z / x-windows / mesa-amiwin / src / stencil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-30  |  27.0 KB  |  1,292 lines

  1. /* stencil.c */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  1.2
  6.  * Copyright (C) 1995  Brian Paul  (brianp@ssec.wisc.edu)
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Library General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Library General Public
  19.  * License along with this library; if not, write to the Free
  20.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23.  
  24. /*
  25. $Id: stencil.c,v 1.12 1995/11/01 15:13:11 brianp Exp $
  26.  
  27. $Log: stencil.c,v $
  28.  * Revision 1.12  1995/11/01  15:13:11  brianp
  29.  * renamed variable operator as oper per Steven Spitz
  30.  *
  31.  * Revision 1.11  1995/07/24  20:35:20  brianp
  32.  * replaced memset() with MEMSET() and memcpy() with MEMCPY()
  33.  *
  34.  * Revision 1.10  1995/06/22  14:26:50  brianp
  35.  * glStencilFunc, glStencilOp, glStencilMask now work in display lists
  36.  *
  37.  * Revision 1.9  1995/06/21  15:10:07  brianp
  38.  * allocate stencil buffer in gl_clear_stencil_buffer() if it doesn't exist
  39.  *
  40.  * Revision 1.8  1995/05/22  21:02:41  brianp
  41.  * Release 1.2
  42.  *
  43.  * Revision 1.7  1995/05/12  16:57:22  brianp
  44.  * replaced CC.Mode!=0 with INSIDE_BEGIN_END
  45.  *
  46.  * Revision 1.6  1995/03/10  16:23:11  brianp
  47.  * added include pb.h
  48.  *
  49.  * Revision 1.5  1995/03/10  15:52:47  brianp
  50.  * change MAX_WIDTH to PB_SIZE in stencil_pixels
  51.  *
  52.  * Revision 1.4  1995/03/09  21:32:28  brianp
  53.  * removed #include stdio.h
  54.  *
  55.  * Revision 1.3  1995/03/04  19:29:44  brianp
  56.  * 1.1 beta revision
  57.  *
  58.  * Revision 1.2  1995/03/01  17:44:36  brianp
  59.  * added stenciling for PB
  60.  *
  61.  * Revision 1.1  1995/02/24  14:28:31  brianp
  62.  * Initial revision
  63.  *
  64.  */
  65.  
  66.  
  67. #include <stdlib.h>
  68. #include <string.h>
  69. #include "context.h"
  70. #include "list.h"
  71. #include "macros.h"
  72. #include "pb.h"
  73. #include "stencil.h"
  74.  
  75.  
  76.  
  77. void glClearStencil( GLint s )
  78. {
  79.    if (CC.CompileFlag) {
  80.       gl_save_clearstencil( s );
  81.    }
  82.    if (CC.ExecuteFlag) {
  83.       if (INSIDE_BEGIN_END) {
  84.      gl_error( GL_INVALID_OPERATION, "glClearStencil" );
  85.      return;
  86.       }
  87.  
  88.       CC.Stencil.Clear = (GLuint) s;
  89.    }
  90. }
  91.  
  92.  
  93.  
  94. void glStencilFunc( GLenum func, GLint ref, GLuint mask )
  95. {
  96.    if (CC.CompileFlag) {
  97.       gl_save_stencilfunc( func, ref, mask );
  98.    }
  99.    if (CC.ExecuteFlag) {
  100.       GLint maxref;
  101.  
  102.       if (INSIDE_BEGIN_END) {
  103.      gl_error( GL_INVALID_OPERATION, "glStencilFunc" );
  104.      return;
  105.       }
  106.  
  107.       switch (func) {
  108.      case GL_NEVER:
  109.      case GL_LESS:
  110.      case GL_LEQUAL:
  111.      case GL_GREATER:
  112.      case GL_GEQUAL:
  113.      case GL_EQUAL:
  114.      case GL_NOTEQUAL:
  115.      case GL_ALWAYS:
  116.         CC.Stencil.Function = func;
  117.         break;
  118.      default:
  119.         gl_error( GL_INVALID_ENUM, "glStencilFunc" );
  120.         return;
  121.       }
  122.  
  123.       maxref = (1 << STENCIL_BITS) - 1;
  124.       CC.Stencil.Ref = CLAMP( ref, 0, maxref );
  125.  
  126.       CC.Stencil.ValueMask = mask;
  127.    }
  128. }
  129.  
  130.  
  131.  
  132. void glStencilMask( GLuint mask )
  133. {
  134.    if (CC.CompileFlag) {
  135.       gl_save_stencilmask( mask );
  136.    }
  137.    if (CC.ExecuteFlag) {
  138.       if (INSIDE_BEGIN_END) {
  139.      gl_error( GL_INVALID_OPERATION, "glStencilMask" );
  140.      return;
  141.       }
  142.       CC.Stencil.WriteMask = mask;
  143.    }
  144. }
  145.  
  146.  
  147.  
  148. void glStencilOp( GLenum fail, GLenum zfail, GLenum zpass )
  149. {
  150.    if (CC.CompileFlag) {
  151.       gl_save_stencilop( fail, zfail, zpass );
  152.    }
  153.    if (CC.ExecuteFlag) {
  154.       if (INSIDE_BEGIN_END) {
  155.      gl_error( GL_INVALID_OPERATION, "glStencilOp" );
  156.      return;
  157.       }
  158.       switch (fail) {
  159.      case GL_KEEP:
  160.      case GL_ZERO:
  161.      case GL_REPLACE:
  162.      case GL_INCR:
  163.      case GL_DECR:
  164.      case GL_INVERT:
  165.         CC.Stencil.FailFunc = fail;
  166.         break;
  167.      default:
  168.         gl_error( GL_INVALID_ENUM, "glStencilOp" );
  169.         return;
  170.       }
  171.       switch (zfail) {
  172.      case GL_KEEP:
  173.      case GL_ZERO:
  174.      case GL_REPLACE:
  175.      case GL_INCR:
  176.      case GL_DECR:
  177.      case GL_INVERT:
  178.         CC.Stencil.ZFailFunc = zfail;
  179.         break;
  180.      default:
  181.         gl_error( GL_INVALID_ENUM, "glStencilOp" );
  182.         return;
  183.       }
  184.       switch (zpass) {
  185.      case GL_KEEP:
  186.      case GL_ZERO:
  187.      case GL_REPLACE:
  188.      case GL_INCR:
  189.      case GL_DECR:
  190.      case GL_INVERT:
  191.         CC.Stencil.ZPassFunc = zpass;
  192.         break;
  193.      default:
  194.         gl_error( GL_INVALID_ENUM, "glStencilOp" );
  195.         return;
  196.       }
  197.    }
  198. }
  199.  
  200.  
  201.  
  202. /* Stencil Logic:
  203.  
  204. IF stencil test fails THEN
  205.    Don't write the pixel (RGBA,Z)
  206.    Execute FailOp
  207. ELSE
  208.    Write the pixel
  209. ENDIF
  210.  
  211. Perform Depth Test
  212.  
  213. IF depth test passes OR no depth buffer THEN
  214.    Execute ZPass
  215.    Write the pixel
  216. ELSE
  217.    Execute ZFail
  218. ENDIF
  219.  
  220. */
  221.  
  222.  
  223.  
  224.  
  225. /*
  226.  * Apply the given stencil operator for each pixel in the span whose
  227.  * mask flag is set.
  228.  * Input:  n - number of pixels in the span
  229.  *         x, y - location of leftmost pixel in the span
  230.  *         oper - the stencil buffer operator
  231.  *         mask - array [n] of flag:  1=apply operator, 0=don't apply operator
  232.  */
  233. static void apply_stencil_op_to_span( GLuint n, GLint x, GLint y,
  234.                       GLenum oper, GLubyte mask[] )
  235. {
  236.    register GLuint i, j;
  237.    register GLuint r, s;
  238.    register GLuint wrtmask, invmask;
  239.  
  240.    wrtmask = CC.Stencil.WriteMask;
  241.    invmask = !CC.Stencil.WriteMask;
  242.  
  243.    r = CC.Stencil.Ref;
  244.    j = y * CC.BufferWidth + x;
  245.  
  246.    switch (oper) {
  247.       case GL_KEEP:
  248.          /* do nothing */
  249.          break;
  250.       case GL_ZERO:
  251.      if (invmask==0) {
  252.         for (i=0;i<n;i++,j++) {
  253.            if (mask[i]) {
  254.           CC.StencilBuffer[j] = 0;
  255.            }
  256.         }
  257.      }
  258.      else {
  259.         for (i=0;i<n;i++,j++) {
  260.            if (mask[i]) {
  261.           s = CC.StencilBuffer[j];
  262.           CC.StencilBuffer[j] = invmask & s;
  263.            }
  264.         }
  265.      }
  266.      break;
  267.       case GL_REPLACE:
  268.      if (invmask==0) {
  269.         for (i=0;i<n;i++,j++) {
  270.            if (mask[i]) {
  271.           CC.StencilBuffer[j] = r;
  272.            }
  273.         }
  274.      }
  275.      else {
  276.         for (i=0;i<n;i++,j++) {
  277.            if (mask[i]) {
  278.           s = CC.StencilBuffer[j];
  279.           CC.StencilBuffer[j] = (invmask & s ) | (wrtmask & r);
  280.            }
  281.         }
  282.      }
  283.      break;
  284.       case GL_INCR:
  285.      if (invmask==0) {
  286.         for (i=0;i<n;i++,j++) {
  287.            if (mask[i]) {
  288.           s = CC.StencilBuffer[j];
  289.           if (s<0xff) {
  290.              CC.StencilBuffer[j] = s+1;
  291.           }
  292.            }
  293.         }
  294.      }
  295.      else {
  296.         for (i=0;i<n;i++,j++) {
  297.            if (mask[i]) {
  298.           /* VERIFY logic of adding 1 to a write-masked value */
  299.           s = CC.StencilBuffer[j];
  300.           if (s<0xff) {
  301.              CC.StencilBuffer[j] = (invmask & s) | (wrtmask & (s+1));
  302.           }
  303.            }
  304.         }
  305.      }
  306.      break;
  307.       case GL_DECR:
  308.      if (invmask==0) {
  309.         for (i=0;i<n;i++,j++) {
  310.            if (mask[i]) {
  311.           s = CC.StencilBuffer[j];
  312.           if (s>0) {
  313.              CC.StencilBuffer[j] = s-1;
  314.           }
  315.            }
  316.         }
  317.      }
  318.      else {
  319.         for (i=0;i<n;i++,j++) {
  320.            if (mask[i]) {
  321.           /* VERIFY logic of subtracting 1 to a write-masked value */
  322.           s = CC.StencilBuffer[j];
  323.           if (s>0) {
  324.              CC.StencilBuffer[j] = (invmask & s) | (wrtmask & (s-1));
  325.           }
  326.            }
  327.         }
  328.      }
  329.      break;
  330.       case GL_INVERT:
  331.      if (invmask==0) {
  332.         for (i=0;i<n;i++,j++) {
  333.            if (mask[i]) {
  334.           s = CC.StencilBuffer[j];
  335.           CC.StencilBuffer[j] = !s;
  336.            }
  337.         }
  338.      }
  339.      else {
  340.         for (i=0;i<n;i++,j++) {
  341.            if (mask[i]) {
  342.           s = CC.StencilBuffer[j];
  343.           CC.StencilBuffer[j] = (invmask & s) | (wrtmask & !s);
  344.            }
  345.         }
  346.      }
  347.      break;
  348.       default:
  349.      gl_error( GL_INVALID_ENUM, "gl_stencil error 2" );
  350.      return;
  351.    }
  352. }
  353.  
  354.  
  355.  
  356.  
  357. /*
  358.  * Apply stencil test to a span of pixels before depth buffering.
  359.  * Input:  n - number of pixels in the span
  360.  *         x, y - coordinate of left-most pixel in the span
  361.  *         mask - array [n] of flag:  0=skip the pixel, 1=stencil the pixel
  362.  * Output:  mask - pixels which fail the stencil test will have their
  363.  *                 mask flag set to 0.
  364.  * Return:  0 = all pixels failed, 1 = zero or more pixels passed.
  365.  */
  366. GLint gl_stencil_span( GLuint n, GLint x, GLint y, GLubyte mask[] )
  367. {
  368.    GLubyte fail[MAX_WIDTH];
  369.    register GLuint r, s;
  370.    register GLuint i, j;
  371.    GLint allfail = 0;
  372.  
  373.    /*
  374.     * Perform stencil test.  The results of this operation are stored
  375.     * in the fail[] array:
  376.     *   IF fail[i] is non-zero THEN
  377.     *       the stencil fail operator is to be applied
  378.     *   ELSE
  379.     *       the stencil fail operator is not to be applied
  380.     *   ENDIF
  381.     */
  382.    j = y * CC.BufferWidth + x;
  383.    switch (CC.Stencil.Function) {
  384.       case GL_NEVER:
  385.          /* always fail */
  386.          for (i=0;i<n;i++) {
  387.         if (mask[i]) {
  388.            mask[i] = 0;
  389.            fail[i] = 1;
  390.         }
  391.         else {
  392.            fail[i] = 0;
  393.         }
  394.      }
  395.      allfail = 1;
  396.      break;
  397.       case GL_LESS:
  398.      r = CC.Stencil.Ref & CC.Stencil.ValueMask;
  399.      for (i=0;i<n;i++,j++) {
  400.         if (mask[i]) {
  401.            s = CC.StencilBuffer[j] & CC.Stencil.ValueMask;
  402.            if (r < s) {
  403.           /* passed */
  404.           fail[i] = 0;
  405.            }
  406.            else {
  407.           fail[i] = 1;
  408.           mask[i] = 0;
  409.            }
  410.         }
  411.         else {
  412.            fail[i] = 0;
  413.         }
  414.      }
  415.      break;
  416.       case GL_LEQUAL:
  417.      r = CC.Stencil.Ref & CC.Stencil.ValueMask;
  418.      for (i=0;i<n;i++,j++) {
  419.         if (mask[i]) {
  420.            s = CC.StencilBuffer[j] & CC.Stencil.ValueMask;
  421.            if (r <= s) {
  422.           /* pass */
  423.           fail[i] = 0;
  424.            }
  425.            else {
  426.           fail[i] = 1;
  427.           mask[i] = 0;
  428.            }
  429.         }
  430.         else {
  431.            fail[i] = 0;
  432.         }
  433.      }
  434.      break;
  435.       case GL_GREATER:
  436.      r = CC.Stencil.Ref & CC.Stencil.ValueMask;
  437.      for (i=0;i<n;i++,j++) {
  438.         if (mask[i]) {
  439.            s = CC.StencilBuffer[j] & CC.Stencil.ValueMask;
  440.            if (r > s) {
  441.           /* passed */
  442.           fail[i] = 0;
  443.            }
  444.            else {
  445.           fail[i] = 1;
  446.           mask[i] = 0;
  447.            }
  448.         }
  449.         else {
  450.            fail[i] = 0;
  451.         }
  452.      }
  453.      break;
  454.       case GL_GEQUAL:
  455.      r = CC.Stencil.Ref & CC.Stencil.ValueMask;
  456.      for (i=0;i<n;i++,j++) {
  457.         if (mask[i]) {
  458.            s = CC.StencilBuffer[j] & CC.Stencil.ValueMask;
  459.            if (r <= s) {
  460.           /* passed */
  461.           fail[i] = 0;
  462.            }
  463.            else {
  464.           fail[i] = 1;
  465.           mask[i] = 0;
  466.            }
  467.         }
  468.         else {
  469.            fail[i] = 0;
  470.         }
  471.      }
  472.      break;
  473.       case GL_EQUAL:
  474.      r = CC.Stencil.Ref & CC.Stencil.ValueMask;
  475.      for (i=0;i<n;i++,j++) {
  476.         if (mask[i]) {
  477.            s = CC.StencilBuffer[j] & CC.Stencil.ValueMask;
  478.            if (r == s) {
  479.           /* passed */
  480.           fail[i] = 0;
  481.            }
  482.            else {
  483.           fail[i] = 1;
  484.           mask[i] = 0;
  485.            }
  486.         }
  487.         else {
  488.            fail[i] = 0;
  489.         }
  490.      }
  491.      break;
  492.       case GL_NOTEQUAL:
  493.      r = CC.Stencil.Ref & CC.Stencil.ValueMask;
  494.      for (i=0;i<n;i++,j++) {
  495.         if (mask[i]) {
  496.            s = CC.StencilBuffer[j] & CC.Stencil.ValueMask;
  497.            if (r != s) {
  498.           /* passed */
  499.           fail[i] = 0;
  500.            }
  501.            else {
  502.           fail[i] = 1;
  503.           mask[i] = 0;
  504.            }
  505.         }
  506.         else {
  507.            fail[i] = 0;
  508.         }
  509.      }
  510.      break;
  511.       case GL_ALWAYS:
  512.      /* always pass */
  513.      for (i=0;i<n;i++) {
  514.         fail[i] = 0;
  515.      }
  516.      break;
  517.       default:
  518.      gl_error( GL_INVALID_ENUM, "gl_stencil error 1" );
  519.      return 0;
  520.    }
  521.  
  522.    apply_stencil_op_to_span( n, x, y, CC.Stencil.FailFunc, fail );
  523.  
  524.    return (allfail) ? 0 : 1;
  525. }
  526.  
  527.  
  528.  
  529.  
  530. /*
  531.  * Apply the combination depth-buffer/stencil operator to a span of pixels.
  532.  * Input:  n - number of pixels in the span
  533.  *         x, y - location of leftmost pixel in span
  534.  *         z - array [n] of z values
  535.  * Input:  mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
  536.  * Output:  mask - array [n] of flags (1=depth test passed, 0=failed) 
  537.  */
  538. void gl_depth_stencil_span( GLuint n, GLint x, GLint y, GLint z[],
  539.                 GLubyte mask[] )
  540. {
  541.    if (CC.Depth.Test==GL_FALSE) {
  542.       /*
  543.        * No depth buffer, just apply zpass stencil function to active pixels.
  544.        */
  545.       apply_stencil_op_to_span( n, x, y, CC.Stencil.ZPassFunc, mask );
  546.    }
  547.    else {
  548.       /*
  549.        * Perform depth buffering, then apply zpass or zfail stencil function.
  550.        */
  551.       GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH];
  552.       register GLuint i;
  553.       GLint dummyz[MAX_WIDTH];
  554.       GLint *zptr;
  555.  
  556.       /* init pass and fail masks to zero */
  557.       for (i=0;i<n;i++) {
  558.      passmask[i] = failmask[i] = 0;
  559.       }
  560.  
  561.       zptr = CC.DepthBuffer + y * CC.BufferWidth + x;
  562.  
  563.       if (CC.Depth.Mask==GL_FALSE) {
  564.      /* The depth buffer is write protected.  Copy current z values
  565.       * for the pixel span to a dummy array then use the dummy array
  566.       * as the depth buffer.  This way, the real z-buffer isn't modified
  567.       * and the code below is simpler.  Not a big performance hit since
  568.       * the depth buffer is usually not write protected.
  569.       */
  570.      for (i=0;i<n;i++) {
  571.         dummyz[i] = *zptr++;
  572.      }
  573.      zptr = dummyz;
  574.       }
  575.  
  576.       switch (CC.Depth.Func) {
  577.      case GL_LESS:
  578.         for (i=0; i<n; i++,zptr++) {
  579.            if (mask[i]) {
  580.           if (z[i] < *zptr) {
  581.              /* passed */
  582.              *zptr = z[i];
  583.              passmask[i] = 1;
  584.           }
  585.           else {
  586.              /* failed */
  587.              mask[i] = 0;
  588.              failmask[i] = 1;
  589.           }
  590.            }
  591.         }
  592.             break;
  593.          case GL_LEQUAL:
  594.         for (i=0; i<n; i++,zptr++) {
  595.            if (mask[i]) {
  596.           if (z[i] <= *zptr) {
  597.              /* passed */
  598.              *zptr = z[i];
  599.              passmask[i] = 1;
  600.           }
  601.           else {
  602.              /* failed */
  603.              mask[i] = 0;
  604.              failmask[i] = 1;
  605.           }
  606.            }
  607.         }
  608.             break;
  609.          case GL_GEQUAL:
  610.         for (i=0; i<n; i++,zptr++) {
  611.            if (mask[i]) {
  612.           if (z[i] >= *zptr) {
  613.              /* passed */
  614.              *zptr = z[i];
  615.              passmask[i] = 1;
  616.           }
  617.           else {
  618.              /* failed */
  619.              mask[i] = 0;
  620.              failmask[i] = 1;
  621.           }
  622.            }
  623.         }
  624.             break;
  625.          case GL_GREATER:
  626.         for (i=0; i<n; i++,zptr++) {
  627.            if (mask[i]) {
  628.           if (z[i] > *zptr) {
  629.              /* passed */
  630.              *zptr = z[i];
  631.              passmask[i] = 1;
  632.           }
  633.           else {
  634.              /* failed */
  635.              mask[i] = 0;
  636.              failmask[i] = 1;
  637.           }
  638.            }
  639.         }
  640.             break;
  641.          case GL_NOTEQUAL:
  642.         for (i=0; i<n; i++,zptr++) {
  643.            if (mask[i]) {
  644.           if (z[i] != *zptr) {
  645.              /* passed */
  646.              *zptr = z[i];
  647.              passmask[i] = 1;
  648.           }
  649.           else {
  650.              /* failed */
  651.              mask[i] = 0;
  652.              failmask[i] = 1;
  653.           }
  654.            }
  655.         }
  656.             break;
  657.          case GL_EQUAL:
  658.         for (i=0; i<n; i++,zptr++) {
  659.            if (mask[i]) {
  660.           if (z[i] == *zptr) {
  661.              /* passed */
  662.              *zptr = z[i];
  663.              passmask[i] = 1;
  664.           }
  665.           else {
  666.              /* failed */
  667.              mask[i] = 0;
  668.              failmask[i] = 1;
  669.           }
  670.            }
  671.         }
  672.             break;
  673.          case GL_ALWAYS:
  674.         for (i=0; i<n; i++,zptr++) {
  675.            if (mask[i]) {
  676.           /* depth test always pass */
  677.           *zptr = z[i];
  678.           passmask[i] = 1;
  679.            }
  680.         }
  681.             break;
  682.          case GL_NEVER:
  683.         for (i=0; i<n; i++) {
  684.            if (mask[i]) {
  685.           /* depth test always fails */
  686.           mask[i] = 0;
  687.           failmask[i] = 1;
  688.            }
  689.         }
  690.             break;
  691.      default:
  692.         gl_error( GL_INVALID_ENUM, "gl_depth_stencil" );
  693.       }
  694.  
  695.       /* apply the pass and fail operations */
  696.       apply_stencil_op_to_span( n, x, y, CC.Stencil.ZFailFunc, failmask );
  697.       apply_stencil_op_to_span( n, x, y, CC.Stencil.ZPassFunc, passmask );
  698.    }
  699.  
  700. }
  701.  
  702.  
  703.  
  704. #define OFFSET( X, Y )    ( (Y) * CC.BufferWidth + (X) )
  705.  
  706.  
  707.  
  708. /*
  709.  * Apply the given stencil operator for each pixel in the array whose
  710.  * mask flag is set.
  711.  * Input:  n - number of pixels in the span
  712.  *         x, y - array of [n] pixels
  713.  *         operator - the stencil buffer operator
  714.  *         mask - array [n] of flag:  1=apply operator, 0=don't apply operator
  715.  */
  716. static void apply_stencil_op_to_pixels( GLuint n, const GLint x[],
  717.                         const GLint y[],
  718.                         GLenum oper, GLubyte mask[] )
  719. {
  720.    register GLuint i, j;
  721.    register GLuint r, s;
  722.    register GLuint wrtmask, invmask;
  723.  
  724.    wrtmask = CC.Stencil.WriteMask;
  725.    invmask = !CC.Stencil.WriteMask;
  726.  
  727.    r = CC.Stencil.Ref;
  728.  
  729.    switch (oper) {
  730.       case GL_KEEP:
  731.          /* do nothing */
  732.          break;
  733.       case GL_ZERO:
  734.      if (invmask==0) {
  735.         for (i=0;i<n;i++) {
  736.            if (mask[i]) {
  737.           j = OFFSET(x[i],y[i]);
  738.           CC.StencilBuffer[j] = 0;
  739.            }
  740.         }
  741.      }
  742.      else {
  743.         for (i=0;i<n;i++) {
  744.            if (mask[i]) {
  745.           j = OFFSET(x[i],y[i]);
  746.           s = CC.StencilBuffer[j];
  747.           CC.StencilBuffer[j] = invmask & s;
  748.            }
  749.         }
  750.      }
  751.      break;
  752.       case GL_REPLACE:
  753.      if (invmask==0) {
  754.         for (i=0;i<n;i++) {
  755.            if (mask[i]) {
  756.           j = OFFSET(x[i],y[i]);
  757.           CC.StencilBuffer[j] = r;
  758.            }
  759.         }
  760.      }
  761.      else {
  762.         for (i=0;i<n;i++) {
  763.            if (mask[i]) {
  764.           j = OFFSET(x[i],y[i]);
  765.           s = CC.StencilBuffer[j];
  766.           CC.StencilBuffer[j] = (invmask & s ) | (wrtmask & r);
  767.            }
  768.         }
  769.      }
  770.      break;
  771.       case GL_INCR:
  772.      if (invmask==0) {
  773.         for (i=0;i<n;i++) {
  774.            if (mask[i]) {
  775.           j = OFFSET(x[i],y[i]);
  776.           s = CC.StencilBuffer[j];
  777.           if (s<0xff) {
  778.              CC.StencilBuffer[j] = s+1;
  779.           }
  780.            }
  781.         }
  782.      }
  783.      else {
  784.         for (i=0;i<n;i++) {
  785.            if (mask[i]) {
  786.           j = OFFSET(x[i],y[i]);
  787.           /* VERIFY logic of adding 1 to a write-masked value */
  788.           s = CC.StencilBuffer[j];
  789.           if (s<0xff) {
  790.              CC.StencilBuffer[j] = (invmask & s) | (wrtmask & (s+1));
  791.           }
  792.            }
  793.         }
  794.      }
  795.      break;
  796.       case GL_DECR:
  797.      if (invmask==0) {
  798.         for (i=0;i<n;i++) {
  799.            if (mask[i]) {
  800.           j = OFFSET(x[i],y[i]);
  801.           s = CC.StencilBuffer[j];
  802.           if (s>0) {
  803.              CC.StencilBuffer[j] = s-1;
  804.           }
  805.            }
  806.         }
  807.      }
  808.      else {
  809.         for (i=0;i<n;i++) {
  810.            if (mask[i]) {
  811.           j = OFFSET(x[i],y[i]);
  812.           /* VERIFY logic of subtracting 1 to a write-masked value */
  813.           s = CC.StencilBuffer[j];
  814.           if (s>0) {
  815.              CC.StencilBuffer[j] = (invmask & s) | (wrtmask & (s-1));
  816.           }
  817.            }
  818.         }
  819.      }
  820.      break;
  821.       case GL_INVERT:
  822.      if (invmask==0) {
  823.         for (i=0;i<n;i++) {
  824.            if (mask[i]) {
  825.           j = OFFSET(x[i],y[i]);
  826.           s = CC.StencilBuffer[j];
  827.           CC.StencilBuffer[j] = !s;
  828.            }
  829.         }
  830.      }
  831.      else {
  832.         for (i=0;i<n;i++) {
  833.            if (mask[i]) {
  834.           j = OFFSET(x[i],y[i]);
  835.           s = CC.StencilBuffer[j];
  836.           CC.StencilBuffer[j] = (invmask & s) | (wrtmask & !s);
  837.            }
  838.         }
  839.      }
  840.      break;
  841.       default:
  842.      gl_error( GL_INVALID_ENUM, "gl_stencil error 4" );
  843.      return;
  844.    }
  845. }
  846.  
  847.  
  848.  
  849. /*
  850.  * Apply stencil test to an array of pixels before depth buffering.
  851.  * Input:  n - number of pixels in the span
  852.  *         x, y - array of [n] pixels to stencil
  853.  *         mask - array [n] of flag:  0=skip the pixel, 1=stencil the pixel
  854.  * Output:  mask - pixels which fail the stencil test will have their
  855.  *                 mask flag set to 0.
  856.  * Return:  0 = all pixels failed, 1 = zero or more pixels passed.
  857.  */
  858. GLint gl_stencil_pixels( GLuint n, const GLint x[], const GLint y[],
  859.              GLubyte mask[] )
  860. {
  861.    GLubyte fail[PB_SIZE];
  862.    register GLuint r, s;
  863.    register GLuint i, j;
  864.    GLint allfail = 0;
  865.  
  866.    /*
  867.     * Perform stencil test.  The results of this operation are stored
  868.     * in the fail[] array:
  869.     *   IF fail[i] is non-zero THEN
  870.     *       the stencil fail operator is to be applied
  871.     *   ELSE
  872.     *       the stencil fail operator is not to be applied
  873.     *   ENDIF
  874.     */
  875.  
  876.    switch (CC.Stencil.Function) {
  877.       case GL_NEVER:
  878.          /* always fail */
  879.          for (i=0;i<n;i++) {
  880.         if (mask[i]) {
  881.            mask[i] = 0;
  882.            fail[i] = 1;
  883.         }
  884.         else {
  885.            fail[i] = 0;
  886.         }
  887.      }
  888.      allfail = 1;
  889.      break;
  890.       case GL_LESS:
  891.      r = CC.Stencil.Ref & CC.Stencil.ValueMask;
  892.      for (i=0;i<n;i++) {
  893.         if (mask[i]) {
  894.            j = OFFSET(x[i],y[i]);
  895.            s = CC.StencilBuffer[j] & CC.Stencil.ValueMask;
  896.            if (r < s) {
  897.           /* passed */
  898.           fail[i] = 0;
  899.            }
  900.            else {
  901.           fail[i] = 1;
  902.           mask[i] = 0;
  903.            }
  904.         }
  905.         else {
  906.            fail[i] = 0;
  907.         }
  908.      }
  909.      break;
  910.       case GL_LEQUAL:
  911.      r = CC.Stencil.Ref & CC.Stencil.ValueMask;
  912.      for (i=0;i<n;i++) {
  913.         if (mask[i]) {
  914.            j = OFFSET(x[i],y[i]);
  915.            s = CC.StencilBuffer[j] & CC.Stencil.ValueMask;
  916.            if (r <= s) {
  917.           /* pass */
  918.           fail[i] = 0;
  919.            }
  920.            else {
  921.           fail[i] = 1;
  922.           mask[i] = 0;
  923.            }
  924.         }
  925.         else {
  926.            fail[i] = 0;
  927.         }
  928.      }
  929.      break;
  930.       case GL_GREATER:
  931.      r = CC.Stencil.Ref & CC.Stencil.ValueMask;
  932.      for (i=0;i<n;i++) {
  933.         if (mask[i]) {
  934.            j = OFFSET(x[i],y[i]);
  935.            s = CC.StencilBuffer[j] & CC.Stencil.ValueMask;
  936.            if (r > s) {
  937.           /* passed */
  938.           fail[i] = 0;
  939.            }
  940.            else {
  941.           fail[i] = 1;
  942.           mask[i] = 0;
  943.            }
  944.         }
  945.         else {
  946.            fail[i] = 0;
  947.         }
  948.      }
  949.      break;
  950.       case GL_GEQUAL:
  951.      r = CC.Stencil.Ref & CC.Stencil.ValueMask;
  952.      for (i=0;i<n;i++) {
  953.         if (mask[i]) {
  954.            j = OFFSET(x[i],y[i]);
  955.            s = CC.StencilBuffer[j] & CC.Stencil.ValueMask;
  956.            if (r <= s) {
  957.           /* passed */
  958.           fail[i] = 0;
  959.            }
  960.            else {
  961.           fail[i] = 1;
  962.           mask[i] = 0;
  963.            }
  964.         }
  965.         else {
  966.            fail[i] = 0;
  967.         }
  968.      }
  969.      break;
  970.       case GL_EQUAL:
  971.      r = CC.Stencil.Ref & CC.Stencil.ValueMask;
  972.      for (i=0;i<n;i++) {
  973.         if (mask[i]) {
  974.            j = OFFSET(x[i],y[i]);
  975.            s = CC.StencilBuffer[j] & CC.Stencil.ValueMask;
  976.            if (r == s) {
  977.           /* passed */
  978.           fail[i] = 0;
  979.            }
  980.            else {
  981.           fail[i] = 1;
  982.           mask[i] = 0;
  983.            }
  984.         }
  985.         else {
  986.            fail[i] = 0;
  987.         }
  988.      }
  989.      break;
  990.       case GL_NOTEQUAL:
  991.      r = CC.Stencil.Ref & CC.Stencil.ValueMask;
  992.      for (i=0;i<n;i++) {
  993.         if (mask[i]) {
  994.            j = OFFSET(x[i],y[i]);
  995.            s = CC.StencilBuffer[j] & CC.Stencil.ValueMask;
  996.            if (r != s) {
  997.           /* passed */
  998.           fail[i] = 0;
  999.            }
  1000.            else {
  1001.           fail[i] = 1;
  1002.           mask[i] = 0;
  1003.            }
  1004.         }
  1005.         else {
  1006.            fail[i] = 0;
  1007.         }
  1008.      }
  1009.      break;
  1010.       case GL_ALWAYS:
  1011.      /* always pass */
  1012.      for (i=0;i<n;i++) {
  1013.         fail[i] = 0;
  1014.      }
  1015.      break;
  1016.       default:
  1017.      gl_error( GL_INVALID_ENUM, "gl_stencil error 3" );
  1018.      return 0;
  1019.    }
  1020.  
  1021.    apply_stencil_op_to_pixels( n, x, y, CC.Stencil.FailFunc, fail );
  1022.  
  1023.    return (allfail) ? 0 : 1;
  1024. }
  1025.  
  1026.  
  1027.  
  1028.  
  1029. /*
  1030.  * Apply the combination depth-buffer/stencil operator to a span of pixels.
  1031.  * Input:  n - number of pixels in the span
  1032.  *         x, y - array of [n] pixels to stencil
  1033.  *         z - array [n] of z values
  1034.  * Input:  mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
  1035.  * Output:  mask - array [n] of flags (1=depth test passed, 0=failed) 
  1036.  */
  1037. void gl_depth_stencil_pixels( GLuint n, const GLint x[], const GLint y[],
  1038.                   const GLint z[], GLubyte mask[] )
  1039. {
  1040.    if (CC.Depth.Test==GL_FALSE) {
  1041.       /*
  1042.        * No depth buffer, just apply zpass stencil function to active pixels.
  1043.        */
  1044.       apply_stencil_op_to_pixels( n, x, y, CC.Stencil.ZPassFunc, mask );
  1045.    }
  1046.    else {
  1047.       /*
  1048.        * Perform depth buffering, then apply zpass or zfail stencil function.
  1049.        */
  1050.       GLubyte passmask[PB_SIZE], failmask[PB_SIZE];
  1051.       register GLuint i;
  1052.       register GLint *zptr;
  1053.  
  1054.       /* init pass and fail masks to zero */
  1055.       for (i=0;i<n;i++) {
  1056.      passmask[i] = failmask[i] = 0;
  1057.       }
  1058.  
  1059.       if (CC.Depth.Mask==GL_FALSE) {
  1060.      /* We can't handle this case right now!  The depth buffer
  1061.       * WILL BE updated.  The solution is to add even more tests
  1062.       * below...
  1063.       */
  1064.       }
  1065.  
  1066.       switch (CC.Depth.Func) {
  1067.      case GL_LESS:
  1068.         for (i=0; i<n; i++) {
  1069.            if (mask[i]) {
  1070.           zptr = CC.DepthBuffer + OFFSET(x[i],y[i]);
  1071.           if (z[i] < *zptr) {
  1072.              /* passed */
  1073.              *zptr = z[i];
  1074.              passmask[i] = 1;
  1075.           }
  1076.           else {
  1077.              /* failed */
  1078.              mask[i] = 0;
  1079.              failmask[i] = 1;
  1080.           }
  1081.            }
  1082.         }
  1083.             break;
  1084.          case GL_LEQUAL:
  1085.         for (i=0; i<n; i++) {
  1086.            if (mask[i]) {
  1087.           zptr = CC.DepthBuffer + OFFSET(x[i],y[i]);
  1088.           if (z[i] <= *zptr) {
  1089.              /* passed */
  1090.              *zptr = z[i];
  1091.              passmask[i] = 1;
  1092.           }
  1093.           else {
  1094.              /* failed */
  1095.              mask[i] = 0;
  1096.              failmask[i] = 1;
  1097.           }
  1098.            }
  1099.         }
  1100.             break;
  1101.          case GL_GEQUAL:
  1102.         for (i=0; i<n; i++) {
  1103.            if (mask[i]) {
  1104.           zptr = CC.DepthBuffer + OFFSET(x[i],y[i]);
  1105.           if (z[i] >= *zptr) {
  1106.              /* passed */
  1107.              *zptr = z[i];
  1108.              passmask[i] = 1;
  1109.           }
  1110.           else {
  1111.              /* failed */
  1112.              mask[i] = 0;
  1113.              failmask[i] = 1;
  1114.           }
  1115.            }
  1116.         }
  1117.             break;
  1118.          case GL_GREATER:
  1119.         for (i=0; i<n; i++) {
  1120.            if (mask[i]) {
  1121.           zptr = CC.DepthBuffer + OFFSET(x[i],y[i]);
  1122.           if (z[i] > *zptr) {
  1123.              /* passed */
  1124.              *zptr = z[i];
  1125.              passmask[i] = 1;
  1126.           }
  1127.           else {
  1128.              /* failed */
  1129.              mask[i] = 0;
  1130.              failmask[i] = 1;
  1131.           }
  1132.            }
  1133.         }
  1134.             break;
  1135.          case GL_NOTEQUAL:
  1136.         for (i=0; i<n; i++) {
  1137.            if (mask[i]) {
  1138.           zptr = CC.DepthBuffer + OFFSET(x[i],y[i]);
  1139.           if (z[i] != *zptr) {
  1140.              /* passed */
  1141.              *zptr = z[i];
  1142.              passmask[i] = 1;
  1143.           }
  1144.           else {
  1145.              /* failed */
  1146.              mask[i] = 0;
  1147.              failmask[i] = 1;
  1148.           }
  1149.            }
  1150.         }
  1151.             break;
  1152.          case GL_EQUAL:
  1153.         for (i=0; i<n; i++) {
  1154.            if (mask[i]) {
  1155.           zptr = CC.DepthBuffer + OFFSET(x[i],y[i]);
  1156.           if (z[i] == *zptr) {
  1157.              /* passed */
  1158.              *zptr = z[i];
  1159.              passmask[i] = 1;
  1160.           }
  1161.           else {
  1162.              /* failed */
  1163.              mask[i] = 0;
  1164.              failmask[i] = 1;
  1165.           }
  1166.            }
  1167.         }
  1168.             break;
  1169.          case GL_ALWAYS:
  1170.         for (i=0; i<n; i++) {
  1171.            if (mask[i]) {
  1172.           zptr = CC.DepthBuffer + OFFSET(x[i],y[i]);
  1173.           /* depth test always pass */
  1174.           *zptr = z[i];
  1175.           passmask[i] = 1;
  1176.            }
  1177.         }
  1178.             break;
  1179.          case GL_NEVER:
  1180.         for (i=0; i<n; i++) {
  1181.            if (mask[i]) {
  1182.           /* depth test always fails */
  1183.           mask[i] = 0;
  1184.           failmask[i] = 1;
  1185.            }
  1186.         }
  1187.             break;
  1188.      default:
  1189.         gl_error( GL_INVALID_ENUM, "gl_depth_stencil" );
  1190.       }
  1191.  
  1192.       /* apply the pass and fail operations */
  1193.       apply_stencil_op_to_pixels( n, x, y, CC.Stencil.ZFailFunc, failmask );
  1194.       apply_stencil_op_to_pixels( n, x, y, CC.Stencil.ZPassFunc, passmask );
  1195.    }
  1196.  
  1197. }
  1198.  
  1199.  
  1200.  
  1201. /*
  1202.  * Return a span of stencil values from the stencil buffer.
  1203.  * Input:  n - how many pixels
  1204.  *         x,y - location of first pixel
  1205.  * Output:  stencil - the array of stencil values
  1206.  */
  1207. void gl_read_stencil_span( GLuint n, GLint x, GLint y, GLubyte stencil[] )
  1208. {
  1209.    GLubyte *s;
  1210.  
  1211.    if (CC.StencilBuffer) {
  1212.       s = CC.StencilBuffer + y * CC.BufferWidth + x;
  1213.       MEMCPY( stencil, s, n * sizeof(GLubyte) );
  1214.    }
  1215. }
  1216.  
  1217.  
  1218.  
  1219. /*
  1220.  * Write a span of stencil values to the stencil buffer.
  1221.  * Input:  n - how many pixels
  1222.  *         x,y - location of first pixel
  1223.  *         stencil - the array of stencil values
  1224.  */
  1225. void gl_write_stencil_span( GLuint n, GLint x, GLint y,
  1226.                 const GLubyte stencil[] )
  1227. {
  1228.    GLubyte *s;
  1229.  
  1230.    if (CC.StencilBuffer) {
  1231.       s = CC.StencilBuffer + y * CC.BufferWidth + x;
  1232.       MEMCPY( s, stencil, n * sizeof(GLubyte) );
  1233.    }
  1234. }
  1235.  
  1236.  
  1237.  
  1238.  
  1239. void gl_alloc_stencil_buffer( void )
  1240. {
  1241.    GLuint buffersize;
  1242.  
  1243.    buffersize = CC.BufferWidth * CC.BufferHeight;
  1244.  
  1245.    /* deallocate current stencil buffer if present */
  1246.    if (CC.StencilBuffer) {
  1247.       free(CC.StencilBuffer);
  1248.       CC.StencilBuffer = NULL;
  1249.    }
  1250.  
  1251.    /* allocate new stencil buffer */
  1252.    CC.StencilBuffer = (GLubyte *) malloc( buffersize * sizeof(GLubyte) );
  1253.    if (!CC.StencilBuffer) {
  1254.       /* out of memory */
  1255.       CC.Stencil.Enabled = GL_FALSE;
  1256.       gl_error( GL_OUT_OF_MEMORY, "gl_alloc_stencil_buffer" );
  1257.    }
  1258. }
  1259.  
  1260.  
  1261.  
  1262.  
  1263. /*
  1264.  * Clear the stencil buffer.  If the stencil buffer doesn't exist yet we'll
  1265.  * allocate it now.
  1266.  */
  1267. void gl_clear_stencil_buffer( void )
  1268. {
  1269.    if (!CC.StencilBuffer) {
  1270.       gl_alloc_stencil_buffer();
  1271.    }
  1272.  
  1273.    if (CC.StencilBuffer) {
  1274.       if (CC.Scissor.Enabled) {
  1275.      GLuint i, x, y;
  1276.      for (y=CC.Scissor.Ymin; y<=CC.Scissor.Ymax; y++) {
  1277.         for (x=CC.Scissor.Xmin; x<=CC.Scissor.Xmax; x++) {
  1278.            i = y * CC.BufferWidth + x;
  1279.            CC.StencilBuffer[i] = CC.Stencil.Clear;
  1280.         }
  1281.      }
  1282.       }
  1283.       else {
  1284.      GLuint i;
  1285.      GLuint buffersize = CC.BufferWidth * CC.BufferHeight;
  1286.      for (i=0;i<buffersize;i++) {
  1287.         CC.StencilBuffer[i] = CC.Stencil.Clear;
  1288.      }
  1289.       }
  1290.    }
  1291. }
  1292.